/*
----------------------------------------------------------------------------
Copyright (c) 2005 - 2008, Wangxing SHI	<swxlion@gmail.com>

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above
	  copyright notice, this list of conditions and the
	  following disclaimer.

    * Redistributions in binary form must reproduce the above
	  copyright notice, this list of conditions and the following
	  disclaimer in the documentation and/or other materials
	  provided with the distribution.

    * Neither the copyright holder's name nor the names of its
	  contributors may be used to endorse or promote products
	  derived from this software without specific prior written
	  permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------
*/

/*--------------------------- TBasalDataNode.h ----------------------------*/
/*===========================================================================
FILE: TBasalDataNode.h
Author: Wangxing SHI (swxlion)
Version: 0.0.2 
Date: 2008-03-25

File Description:
    C++ template for the Double Linked List Node & Double Linked List.
	(The node self is the list.)

Dependencies:
    Platform: Platform Independent.

History:
    version        author        date       description
	----------------------------------------------------
	0.0.1          swxlion       06-09-06   Created the first version. 
	0.0.2          swxlion       08-03-25   Integrated in the ASDL namespace.
===========================================================================*/
#ifndef _APPLICATION_SERVER_DEVELOPMENT_LIBRARY__TBASALDATANODE_H_
#define _APPLICATION_SERVER_DEVELOPMENT_LIBRARY__TBASALDATANODE_H_

/*===============================================================================
  CLASS & STRUCTURE DEFINITIONS
=============================================================================== */
namespace ASDL
{
	/*========================================
	  The Generic Double Linked List & Node
	  (Can't be used in Circular Linked List.)
	==========================================*/
	template < typename T >
	class TDLinkNode
	{
	public:
		T				Data;							//-- Must be the first field. Facilitate for the explicit conversion.
		TDLinkNode*		Pre;
		TDLinkNode*		Next;

		TDLinkNode(): Pre(0), Next(0) 
		{
		}

		TDLinkNode(const T & TypeData): Data(TypeData), Pre(0), Next(0) 
		{
		}

		inline bool Append( TDLinkNode* pNewNode )		//-- Append to the end. Can't be used with an invaild pointer (e.g. a head pointer of an empty list).
		{
			if( !pNewNode )
				return false;

			TDLinkNode* pTempNode = this;
			while( pTempNode->Next )
			{
				pTempNode = pTempNode->Next;
			}
			pTempNode->Next = pNewNode;
			pNewNode->Pre = pTempNode;
			return true;		
		}

		inline bool Append( TDLinkNode* pNewNode, TDLinkNode** ppAnyNodeInList )	//-- Append to the end. Can be used with any node and a NULL pointer (The pointer is the head pointer of an empty list).
		{
			if( !pNewNode || !ppAnyNodeInList )
				return false;

			if( !*ppAnyNodeInList )
			{
				*ppAnyNodeInList = pNewNode;
				return true;
			}

			TDLinkNode* pTempNode = *ppAnyNodeInList;
			while( pTempNode->Next )
			{
				pTempNode = pTempNode->Next;
			}
			pTempNode->Next = pNewNode;
			pNewNode->Pre = pTempNode;
			return true;		
		}

		inline bool Append( TDLinkNode* pNewNode, TDLinkNode* &pAnyNodeInList )	//-- Append to the end. Can be used with any node and a NULL pointer (The pointer is the head pointer of an empty list).
		{
			if( !pNewNode )
				return false;

			if( !pAnyNodeInList )
			{
				pAnyNodeInList = pNewNode;
				return true;
			}

			TDLinkNode* pTempNode = pAnyNodeInList;
			while( pTempNode->Next )
			{
				pTempNode = pTempNode->Next;
			}
			pTempNode->Next = pNewNode;
			pNewNode->Pre = pTempNode;
			return true;		
		}

		inline void Remove()		//-- Remove this node, but don't delete. Can't be used with circular list or the head node of list, so, it don't become to the destructor.
		{
			if( Pre )
				if( Next )
				{
					Next->Pre = Pre;
					Pre->Next = Next;
				}
				else
					Pre->Next = NULL;
			else
				if( Next )
				{
					Next->Pre = NULL;
				}
		}

		inline bool Remove( TDLinkNode** ppHead )	//-- Remove this node, but don't delete. Can be used with the head node of list. Can't be used with circular list.
		{
			if( Pre )
				if( Next )
				{
					Next->Pre = Pre;
					Pre->Next = Next;
				}
				else
					Pre->Next = NULL;
			else
			{
				if( !ppHead || !(*ppHead) )
					return false;
				else
					*ppHead = Next;

				if( Next )
				{
					Next->Pre = NULL;
				}
			}

			return true;
		}

		inline bool Remove( TDLinkNode* &pHead )	//-- Remove this node, but don't delete. Can be used with the head node of list. Can't be used with circular list.
		{
			if( Pre )
				if( Next )
				{
					Next->Pre = Pre;
					Pre->Next = Next;
				}
				else
					Pre->Next = NULL;
			else
			{
				if( !pHead )
					return false;
				else
					pHead = Next;

				if( Next )
				{
					Next->Pre = NULL;
				}
			}

			return true;
		}

		inline void Delete()		//-- Remove and delete this node. Can't be used with circular list or the head node of list, so, it don't become to the destructor.
		{
			Remove();
			delete this;
		}

		inline bool Delete( TDLinkNode** ppHead )	//-- Remove and delete this node. Can be used with the head node of list. Can't be used with circular list.
		{
			if( Pre )
				if( Next )
				{
					Next->Pre = Pre;
					Pre->Next = Next;
				}
				else
					Pre->Next = NULL;
			else
			{
				if( !ppHead || !(*ppHead) )
					return false;
				else
					*ppHead = Next;

				if( Next )
				{
					Next->Pre = NULL;
				}
			}

			delete this;
			return true;
		}

		inline bool Delete( TDLinkNode* &pHead )	//-- Remove and delete this node. Can be used with the head node of list. Can't be used with circular list.
		{
			if( Pre )
				if( Next )
				{
					Next->Pre = Pre;
					Pre->Next = Next;
				}
				else
					Pre->Next = NULL;
			else
			{
				if( !pHead )
					return false;
				else
					pHead = Next;

				if( Next )
				{
					Next->Pre = NULL;
				}
			}

			delete this;
			return true;
		}

		/** If the index overstep the real length, the function will return the data of the last node. */
		inline T& operator[]( int index )
		{
			TDLinkNode* successor = this;

			while( successor->Next && index )
			{
				successor = successor->Next;
				index -= 1;
			}
			return (successor->Data);
		}

		inline unsigned long GetLength()
		{
			unsigned long	len = 1;
			TDLinkNode* successor = this;

			while( successor->Next )
			{
				successor = successor->Next;
				len += 1;
			}
			return len;
		}

		inline unsigned long GetFrontLength()
		{
			unsigned long	len = 0;
			TDLinkNode* precursor = this;

			while( precursor->Pre )
			{
				precursor = precursor->Pre;
				len += 1;
			}
			return len;
		}

		inline unsigned long GetTotalLength()
		{
			return GetFrontLength() + GetLength();
		}

		inline TDLinkNode * GetFirst()
		{
			TDLinkNode*	pNode = this;

			while( pNode->Pre )
				pNode = pNode->Pre;

			return pNode;
		}

		inline TDLinkNode * GetLast()
		{
			TDLinkNode*	pNode = this;

			while( pNode->Next )
				pNode = pNode->Next;

			return pNode;
		}

		inline TDLinkNode * Find( const T &FindData )
		{
			if( this->Data == FindData )
				return this;

			TDLinkNode*	pNode = FindNext(FindData);

			if( pNode == NULL )
				return FindPrevious(FindData);
			else
				return pNode;
		}

		inline TDLinkNode * FindNext( const T &FindData )
		{
			TDLinkNode*	pNode = this;

			while( (pNode = pNode->Next) )
				if( pNode->Data == FindData )
					return pNode;

			return NULL;
		}

		inline TDLinkNode * FindPrevious( const T &FindData )
		{
			TDLinkNode*	pNode = this;

			while( (pNode = pNode->Pre) )
				if( pNode->Data == FindData )
					return pNode;

			return NULL;
		}

		/** The pNode is NOT required in the same list. */
		inline TDLinkNode * Find( TDLinkNode * pNode )
		{
			if( !pNode )
				return NULL;
			else
				return Find(pNode->Data);
		}

		/** The Node is NOT required in the same list. */
		inline TDLinkNode * Find( TDLinkNode & Node )
		{
			return Find(Node.Data);
		}

		/** Just can be used when the pNode in the same list. */
		inline TDLinkNode * FindNext( TDLinkNode * pNode )
		{
			if( !pNode )
				return NULL;

			T	&FindData = pNode->Data;

			while( (pNode = pNode->Next) )
				if( pNode->Data == FindData )
					return pNode;

			return NULL;
		}

		/** Just can be used when the pNode in the same list. */
		inline TDLinkNode * FindPrevious( TDLinkNode * pNode )
		{
			if( !pNode )
				return NULL;

			T	&FindData = pNode->Data;

			while( (pNode = pNode->Pre) )
				if( pNode->Data == FindData )
					return pNode;

			return NULL;
		}
	};
}

#endif // _APPLICATION_SERVER_DEVELOPMENT_LIBRARY__TBASALDATANODE_H_
